﻿using HslCommunication;
using HslCommunication.Core;
using HslCommunication.ModBus;
using Kimd.Common;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Xml.Serialization;

namespace Kimd.Communication
{
    [Serializable]
    public class ModbusTcp : ICommunicationShow
    {
        #region Public Properties
        private ModbusTcpNet busTcpClient = null;
        [XmlIgnore]
        public bool IsConnected { get; set; }
        /// <summary>
        /// 指令合集
        /// </summary>
        [XmlIgnore]
        public SerializableDictionary<string, string> SendCmd
        {
            get
            {
                return Config.SendCmd;
            }
            set
            {
                Config.SendCmd = value;
            }
        }

        public string IpAddress
        {
            get { return Config.IP; }
        }
        public int Port
        {
            get { return Config.Port; }
        }
        public byte StationNo
        {
            get { return Config.StationNo; }
        }
        /// <summary>
        /// 配置文件
        /// </summary>
        public ModbusConfig Config { get; set; } = new ModbusConfig();
        private DataFormat _dataFormat = DataFormat.CDAB;
        public DataFormat DataFormat
        {
            get { return _dataFormat; }
            set
            {
                _dataFormat = value;
                if (busTcpClient != null)
                    busTcpClient.DataFormat = _dataFormat;
            }
        }
        private bool _startWithZero = true;
        public bool StartWithZero
        {
            get { return _startWithZero; }
            set
            {
                _startWithZero = value;
                if (busTcpClient != null)
                    busTcpClient.AddressStartWithZero = _startWithZero;
            }
        }

        #endregion

        #region Constructor

        public ModbusTcp()
        {
        }
        public ModbusTcp(string name) : this()
        {
            Name = name;
        }
        public ModbusTcp(string ipAddress, int port = 502, byte stationNo = 1)
            : this()
        {
            Config.IP = ipAddress;
            Config.Port = port;
            Config.StationNo = stationNo;
        }
        #endregion

        #region Methd

        public bool Connect()
        {
            busTcpClient?.ConnectClose();
            busTcpClient = new ModbusTcpNet(IpAddress, Port, StationNo);
            busTcpClient.AddressStartWithZero = _startWithZero;
            busTcpClient.DataFormat = _dataFormat;

            OperateResult connect = busTcpClient.ConnectServer();
            IsConnected = connect.IsSuccess;
            return connect.IsSuccess;
        }

        public void Close()
        {
            busTcpClient?.ConnectClose();
            IsConnected = false;
        }

        public bool ReadBool(string address, int length, out bool[] data)
        {
            data = null;
            OperateResult<bool[]> or = busTcpClient.ReadCoil(address, (ushort)length);
            if (or.IsSuccess)
            {
                data = or.Content;
                return true;
            }
            return false;
        }
        public bool ReadFloat(string address, int length, out float[] datas)
        {
            datas = null;
            OperateResult<float[]> or = busTcpClient.ReadFloat(address, (ushort)length);
            if (or.IsSuccess)
            {
                datas = or.Content;
                return true;
            }
            return false;
        }
        public bool ReadInt(string address, int length, out int[] datas)
        {
            datas = null;
            OperateResult<int[]> or = busTcpClient.ReadInt32(address, (ushort)length);
            if (or.IsSuccess)
            {
                datas = or.Content;
                return true;
            }
            return false;
        }
        public bool ReadShort(string address, int length, out short[] datas)
        {
            datas = null;
            OperateResult<short[]> or = busTcpClient.ReadInt16(address, (ushort)length);
            if (or.IsSuccess)
            {
                datas = or.Content;
                return true;
            }
            return false;
        }
        public bool WriteBool(string address, bool[] data)
        {
            OperateResult or = busTcpClient.WriteCoil(address, data);
            return or.IsSuccess;
        }
        public bool WriteFloat(string address, float[] datas)
        {
            OperateResult or = busTcpClient.Write(address, datas);
            return or.IsSuccess;
        }
        public bool WriteInt(string address, int[] data)
        {
            OperateResult or = busTcpClient.Write(address, data);
            return or.IsSuccess;
        }
        public bool WriteShort(string address, short[] data)
        {
            OperateResult or = busTcpClient.Write(address, data);
            return or.IsSuccess;
        }

        #endregion

        #region ICommunicationShow
        public CommTypeEnum CommType { get; } = CommTypeEnum.ModbusTCP;
        public string Name { get; set; } = string.Empty;

        public bool IsOpenFlag => IsConnected;

        public object GetConfig()
        {
            return Config;
        }

        public Form GetDebugForm()
        {
            throw new NotImplementedException();
        }

        public List<string> GetShowList()
        {
            return new List<string>();
        }

        public string GetTreeNodeShowStr()
        {
            return $"{Name}(Modbus)({IpAddress}:{Port}-{StationNo})";
        }

        public void SetConfig(object config)
        {
            if (config is ModbusConfig)
            {
                Config = config as ModbusConfig;
            }
        }
        public void SetOpenOrClose(OpenOrClose openOrClose)
        {
            switch (openOrClose)
            {
                case OpenOrClose.Open:
                    Connect();
                    break;
                case OpenOrClose.Close:
                    Close();
                    break;
            }
        }
        #endregion
    }
}
